﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Xml.Linq;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Controls.Primitives;
using System.Windows;
using System.Windows.Markup;

namespace Twi.COMMON.WPF
{
    public static class XElementExtensions
    {
        /// <summary>
        /// 将XElement中的value转换成子节点
        /// </summary>
        /// <param name="me"></param>
        public static void ConvertValueToChildren(this XElement me)
        {
            if (me.Value.Trim().Length > 0)
            {
                try
                {
                    XElement xeContent = XElement.Parse(me.Value.Replace("&gt;", ">").Replace("&lt;", "<"));
                    me.SetValue("");
                    me.Add(xeContent.Elements().ToArray());
                }
                catch { }
            }
        }

        public const string DEFAULT_XMAL_NS = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";

        /// <summary>
        /// 将XElement节点转化成WPF控件
        /// </summary>
        /// <typeparam name="T">WPF控件类型</typeparam>
        /// <param name="me"></param>
        /// <param name="xns">xml命名空间</param>
        /// <returns></returns>
        public static T ConvertToXmalElement<T>(this XElement me, string xns = DEFAULT_XMAL_NS)
        {
            XElement xeCopy = new XElement(XName.Get(me.Name.LocalName, xns));
            foreach (var xattr in me.Attributes())
            {
                if (xns != DEFAULT_XMAL_NS)
                {
                    string attrValue = xattr.Value.Trim();
                    if (attrValue.StartsWith("{Binding")) //自定义控件的属性值设置了绑定，就需要设置相应的命名空间
                    {
                        if (xeCopy.Attributes().SingleOrDefault(j => j.Name.LocalName == "ns_data") == null) //如果没有指定命名空间，就设置为WPF默认的命名空间, 通常肯定要执行这步，配置信息不会加上ns_data
                        {
                            xeCopy.Add(new XAttribute(XName.Get("ns_data", "http://www.w3.org/2000/xmlns/"), "clr-namespace:System.Windows.Data;assembly=PresentationFramework"));
                        }
                        attrValue = attrValue.Replace("{Binding", "{ns_data:Binding");
                    }
                    if (xattr.Name.LocalName.Contains('.'))
                    {
                        xeCopy.Add(new XAttribute(XName.Get(xattr.Name.LocalName, DEFAULT_XMAL_NS), attrValue));
                    }
                    else
                    {
                        xeCopy.Add(new XAttribute(xattr.Name.LocalName, attrValue));
                    }
                }
                else
                {
                    xeCopy.Add(xattr);
                }
            }
            //必须对xeCopy进行字符窜化然后重新解析成XElement才能处理，否则在自定义控件时，属性是Grid.Row时会无法解析该属性，原因不明
            return (T)XamlReader.Load(XElement.Parse(xeCopy.ToString()).CreateReader());
        }


        public static string[] SeperatorArray = new string[] { "Element[", "].Element[", "].Value" };
        public static string[] SeperatorArray_List = new string[] { "Element[", "].Element[", "].Elements" };

        public static string[] SysColumnArray = new string[] { "CreateUserID", "CreateUserName", "CreateDate", "Flag", "LastUpdateUserID", "LastUpdateUserName", "LastUpdateDate" };

        /// <summary>
        /// 将指定容器中的绑定作为节点填充到XElement中
        /// </summary>
        /// <param name="me"></param>
        /// <param name="container"></param>
        public static void PopulateChildrenElement(this XElement me, Grid container)
        {
            List<System.Windows.Controls.Control> ctrlList = new List<System.Windows.Controls.Control>();
            foreach (var child in container.Children.OfType<UIElement>())
            {
                if (child is System.Windows.Controls.Control)
                {
                    ctrlList.Add(child as System.Windows.Controls.Control);
                }
                else
                {
                    if (child is StackPanel)
                    {
                        foreach (var x in (child as StackPanel).Children.OfType<UIElement>().Where(x => x is System.Windows.Controls.Grid))
                        {
                            foreach (var c in (x as Grid).Children.OfType<UIElement>().Where(c => c is System.Windows.Controls.Control))
                            {
                                ctrlList.Add(c as System.Windows.Controls.Control);
                            }
                        }
                        foreach (var x in (child as StackPanel).Children.OfType<UIElement>().Where(x => x is System.Windows.Controls.Control))
                        {
                            ctrlList.Add(x as System.Windows.Controls.Control);
                        }
                    }
                    else
                    {
                        if (child is Canvas)
                        {
                            foreach (var x in (child as Canvas).Children.OfType<UIElement>().Where(x => x is System.Windows.Controls.Control))
                            {
                                ctrlList.Add(x as System.Windows.Controls.Control);
                            }
                        }
                    }
                }
            }

            //按页面选取顺序
            foreach (System.Windows.Controls.Control child in ctrlList.OrderBy(x => x.TabIndex))
            {
                List<BindingExpression> bdExprList = new List<BindingExpression>(); //一个控件可能会有多个绑定
                List<string> bingingXElementNameList = new List<string>(); //指定的绑定XElement名称

                string defaultValue = "";
                if (!(child is System.Windows.FrameworkElement))
                {
                    continue;
                }
                if ((child as System.Windows.FrameworkElement).Visibility != System.Windows.Visibility.Visible)
                {
                    continue;
                }

                if (child is DataGrid)
                {
                    DataGrid dg = child as DataGrid;
                    var bd = dg.GetBindingExpression(DataGrid.ItemsSourceProperty);
                    if (bd == null || bd.ParentBinding.Path == null)
                        continue;
                    var pathList = bd.ParentBinding.Path.Path.Split(SeperatorArray_List, StringSplitOptions.RemoveEmptyEntries);
                    if (pathList.Length == 1)
                    {
                        if (me.Element(pathList[0]) == null)
                        {
                            me.Add(new XElement(pathList[0]));
                        }
                    }
                    else
                    {
                        if (me.Element(pathList[0]) == null)
                        {
                            me.Add(new XElement(pathList[0]));
                        }
                        if (me.Element(pathList[0]).Element(pathList[1]) == null)
                        {
                            me.Element(pathList[0]).Add(new XElement(pathList[1]));
                        }
                    }
                    continue;
                }

                if (child is TextBox)
                {
                    TextBox txt = child as TextBox;
                    var textBdExpr = txt.GetBindingExpression(TextBox.TextProperty);
                    if (txt.Tag == null)
                    {
                        bdExprList.Add(textBdExpr);
                    }
                    else
                    {
                        string elementName = textBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue)); //DisplayName可以用于生成导出模板的列头名称

                    }

                }
                else if (child.GetType() == typeof(ListBox))
                {
                    ListBox lb = child as ListBox;
                    lb.LostFocus += new RoutedEventHandler(lb_LostFocus);
                    var sltBdExpr = lb.GetBindingExpression(ListBox.SelectedValueProperty);
                    if (lb.Tag == null)
                    {
                        bdExprList.Add(sltBdExpr);
                    }
                    else
                    {
                        string elementName = sltBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is ComboBox)
                {
                    ComboBox cbo = child as ComboBox;
                    BindingExpression expr;
                    if (cbo.IsEditable)
                    {
                        expr = cbo.GetBindingExpression(ComboBox.TextProperty);
                        if (expr != null)
                        {
                            cbo.LostFocus += new System.Windows.RoutedEventHandler(cbo_EditableLostFocus);
                        }
                    }
                    else
                    {
                        expr = cbo.GetBindingExpression(ComboBox.SelectedValueProperty);
                        if (expr != null)
                        {
                            cbo.LostFocus += new System.Windows.RoutedEventHandler(cbo_LostFocus);
                        }
                    }

                    if (cbo.Tag == null)
                    {
                        bdExprList.Add(expr);
                    }
                    else
                    {
                        string elementName = expr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                    if (child is UComboBox)
                    {
                        UComboBox gscob = child as UComboBox;
                        if (!string.IsNullOrEmpty(gscob.SelectedValuePath1))
                        {
                            var expr1 = cbo.GetBindingExpression(UComboBox.SelectedValue1Property);
                            bdExprList.Add(expr1);
                            //me.Add(new XElement( expr.ParentBinding.Path.Path.Split(
                            //    new string[] { "Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0]));
                        }
                        if (!string.IsNullOrEmpty(gscob.SelectedValuePath2))
                        {
                            var expr1 = cbo.GetBindingExpression(UComboBox.SelectedValue2Property);
                            bdExprList.Add(expr1);
                            //me.Add(new XElement(expr.ParentBinding.Path.Path.Split(
                            //    new string[] { "Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0]));
                        }
                        if (!string.IsNullOrEmpty(gscob.SelectedValuePath3))
                        {
                            var expr1 = cbo.GetBindingExpression(UComboBox.SelectedValue3Property);
                            bdExprList.Add(expr1);
                            //me.Add(new XElement(expr.ParentBinding.Path.Path.Split(
                            //    new string[] { "Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0]));
                        }
                    }
                }
                else if (child is CheckBox)
                {
                    CheckBox chk = child as CheckBox;
                    defaultValue = "0";//0表示未勾选

                    var chkBdExpr = chk.GetBindingExpression(CheckBox.IsCheckedProperty);
                    if (chk.Tag == null)
                    {
                        bdExprList.Add(chkBdExpr);

                        var isEnabledExpr = chk.GetBindingExpression(CheckBox.IsEnabledProperty);
                        bdExprList.Add(isEnabledExpr);
                    }
                    else
                    {
                        string elementName = chkBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }

                }
                else if (child is DatePicker)
                {
                    DatePicker date = child as DatePicker;
                    var sltBdExpr = date.GetBindingExpression(DatePicker.TextProperty);
                    if (date.Tag == null)
                    {
                        bdExprList.Add(sltBdExpr);
                    }
                    else
                    {
                        string elementName = sltBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is Twi.COMMON.WPF.CtlExtended.DateTimePicker)
                {
                    Twi.COMMON.WPF.CtlExtended.DateTimePicker date = child as Twi.COMMON.WPF.CtlExtended.DateTimePicker;
                    var sltBdExpr = date.GetBindingExpression(Twi.COMMON.WPF.CtlExtended.DateTimePicker.TextProperty);
                    if (date.Tag == null)
                    {
                        bdExprList.Add(sltBdExpr);
                    }
                    else
                    {
                        string elementName = sltBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is Label)
                {
                    Label lbl = child as Label;
                    var ctntBdExpr = lbl.GetBindingExpression(Label.ContentProperty);
                    if (lbl.Tag == null)
                    {
                        bdExprList.Add(ctntBdExpr);
                    }
                    else
                    {
                        string elementName = ctntBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is CodeTextBox)
                {
                    CodeTextBox txt = child as CodeTextBox;
                    var textBdExpr = txt.GetBindingExpression(CodeTextBox.TextProperty);
                    if (txt.Tag == null)
                    {
                        bdExprList.Add(textBdExpr);
                    }
                    else
                    {
                        string elementName = textBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is IChildElement) //自定义的绑定控件
                {
                    IChildElement ce = child as IChildElement;
                    BindingExpression[] beArray = ce.GetBindingExpression();
                    string[] enameArray = ce.GetBindingXElementName();
                    if (beArray != null)
                    {
                        bdExprList.AddRange(beArray);
                    }
                    if (enameArray != null)
                    {
                        bingingXElementNameList.AddRange(enameArray);
                    }
                }
                foreach (BindingExpression bdExpr in bdExprList.Where(x => x != null))
                {
                    string[] bindingElementNames = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries);
                    if (bindingElementNames.Length == 1)
                    {
                        me.Add(new XElement(bindingElementNames[0], defaultValue));
                    }
                    else
                    {
                        if (me.Element(bindingElementNames[0]) == null)
                        {
                            me.Add(new XElement(bindingElementNames[0]));
                        }
                        me.Element(bindingElementNames[0]).Add(new XElement(bindingElementNames[1]));
                    }
                }

                foreach (var s in bingingXElementNameList)
                {
                    if (me.Element(s) == null)
                    {
                        me.Add(new XElement(s));
                    }
                }
            }
        }

        /// <summary>
        /// 将指定容器中的绑定作为节点填充到XElement中
        /// </summary>
        /// <param name="me"></param>
        /// <param name="container"></param>
        public static void PopulateChildrenElement1(this XElement me, Grid container)
        {
            List<System.Windows.Controls.Control> ctrlList = new List<System.Windows.Controls.Control>();
            foreach (var child in container.Children.OfType<UIElement>())
            {
                if (child is System.Windows.Controls.Control)
                {
                    ctrlList.Add(child as System.Windows.Controls.Control);
                }
                else
                {
                    if (child is StackPanel)
                    {
                        foreach (var x in (child as StackPanel).Children.OfType<UIElement>().Where(x => x is System.Windows.Controls.Control))
                        {
                            ctrlList.Add(x as System.Windows.Controls.Control);
                        }
                    }
                    else
                    {
                        if (child is Canvas)
                        {
                            foreach (var x in (child as Canvas).Children.OfType<UIElement>().Where(x => x is System.Windows.Controls.Control))
                            {
                                ctrlList.Add(x as System.Windows.Controls.Control);
                            }
                        }
                    }
                }
            }

            //按页面选取顺序
            foreach (System.Windows.Controls.Control child in ctrlList.OrderBy(x => x.TabIndex))
            {
                List<BindingExpression> bdExprList = new List<BindingExpression>(); //一个控件可能会有多个绑定
                List<string> bingingXElementNameList = new List<string>(); //指定的绑定XElement名称

                string defaultValue = "";
                if (!(child is System.Windows.FrameworkElement))
                {
                    continue;
                }
                if ((child as System.Windows.FrameworkElement).Visibility != System.Windows.Visibility.Visible)
                {
                    continue;
                }

                if (child is DataGrid)
                {
                    DataGrid dg = child as DataGrid;
                    var bd = dg.GetBindingExpression(DataGrid.ItemsSourceProperty);
                    if (bd == null || bd.ParentBinding.Path == null)
                        continue;
                    var pathList = bd.ParentBinding.Path.Path.Split(SeperatorArray_List, StringSplitOptions.RemoveEmptyEntries);
                    if (pathList.Length == 1)
                    {
                        if (me.Element(pathList[0]) == null)
                        {
                            me.Add(new XElement(pathList[0]));
                        }
                    }
                    else
                    {
                        if (me.Element(pathList[0]) == null)
                        {
                            me.Add(new XElement(pathList[0]));
                        }
                        if (me.Element(pathList[0]).Element(pathList[1]) == null)
                        {
                            me.Element(pathList[0]).Add(new XElement(pathList[1]));
                        }
                    }
                    continue;
                }

                if (child is TextBox)
                {
                    TextBox txt = child as TextBox;
                    var textBdExpr = txt.GetBindingExpression(TextBox.TextProperty);
                    if (txt.Tag == null)
                    {
                        bdExprList.Add(textBdExpr);
                    }
                    else
                    {
                        string elementName = textBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue)); //DisplayName可以用于生成导出模板的列头名称

                    }

                }
                else if (child.GetType() == typeof(ListBox))
                {
                    ListBox lb = child as ListBox;
                    var sltBdExpr = lb.GetBindingExpression(ListBox.SelectedValueProperty);
                    if (lb.Tag == null)
                    {
                        bdExprList.Add(sltBdExpr);
                    }
                    else
                    {
                        string elementName = sltBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is ComboBox)
                {
                    ComboBox cbo = child as ComboBox;
                    BindingExpression expr;
                    if (cbo.IsEditable)
                    {
                        expr = cbo.GetBindingExpression(ComboBox.TextProperty);
                        if (expr != null)
                        {
                            cbo.LostFocus += new System.Windows.RoutedEventHandler(cbo_EditableLostFocus);
                        }
                    }
                    else
                    {
                        expr = cbo.GetBindingExpression(ComboBox.SelectedValueProperty);
                        if (expr != null)
                        {
                            cbo.LostFocus += new System.Windows.RoutedEventHandler(cbo_LostFocus);
                        }
                    }

                    if (cbo.Tag == null)
                    {
                        bdExprList.Add(expr);
                    }
                    else
                    {
                        string elementName = expr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                    if (child is UComboBox)
                    {
                        UComboBox gscob = child as UComboBox;
                        if (!string.IsNullOrEmpty(gscob.SelectedValuePath1))
                        {
                            var expr1 = cbo.GetBindingExpression(UComboBox.SelectedValue1Property);
                            bdExprList.Add(expr1);
                            //me.Add(new XElement( expr.ParentBinding.Path.Path.Split(
                            //    new string[] { "Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0]));
                        }
                        if (!string.IsNullOrEmpty(gscob.SelectedValuePath2))
                        {
                            var expr1 = cbo.GetBindingExpression(UComboBox.SelectedValue2Property);
                            bdExprList.Add(expr1);
                            //me.Add(new XElement(expr.ParentBinding.Path.Path.Split(
                            //    new string[] { "Element[", "].Value" }, StringSplitOptions.RemoveEmptyEntries)[0]));
                        }
                        if (!string.IsNullOrEmpty(gscob.SelectedValuePath3))
                        {
                            var expr1 = cbo.GetBindingExpression(UComboBox.SelectedValue3Property);
                            bdExprList.Add(expr1);
                        }
                    }
                }
                else if (child is CheckBox)
                {
                    CheckBox chk = child as CheckBox;
                    defaultValue = "0";//0表示未勾选

                    var chkBdExpr = chk.GetBindingExpression(CheckBox.IsCheckedProperty);
                    if (chk.Tag == null)
                    {
                        bdExprList.Add(chkBdExpr);

                        var isEnabledExpr = chk.GetBindingExpression(CheckBox.IsEnabledProperty);
                        bdExprList.Add(isEnabledExpr);
                    }
                    else
                    {
                        string elementName = chkBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }

                }
                else if (child is DatePicker)
                {
                    DatePicker date = child as DatePicker;
                    var sltBdExpr = date.GetBindingExpression(DatePicker.TextProperty);
                    if (date.Tag == null)
                    {
                        bdExprList.Add(sltBdExpr);
                    }
                    else
                    {
                        string elementName = sltBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is Label)
                {
                    Label lbl = child as Label;
                    var ctntBdExpr = lbl.GetBindingExpression(Label.ContentProperty);
                    if (lbl.Tag == null)
                    {
                        bdExprList.Add(ctntBdExpr);
                    }
                    else
                    {
                        string elementName = ctntBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is CodeTextBox)
                {
                    CodeTextBox txt = child as CodeTextBox;
                    var textBdExpr = txt.GetBindingExpression(CodeTextBox.TextProperty);
                    if (txt.Tag == null)
                    {
                        bdExprList.Add(textBdExpr);
                    }
                    else
                    {
                        string elementName = textBdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
                        string elementDisplayName = child.Tag.ToString();
                        me.Add(new XElement(elementName
                            , new XAttribute("DisplayName", elementDisplayName)
                            , new XAttribute("DisplayWidth", child.Width)
                            , defaultValue));
                    }
                }
                else if (child is IChildElement) //自定义的绑定控件
                {
                    IChildElement ce = child as IChildElement;
                    BindingExpression[] beArray = ce.GetBindingExpression();
                    string[] enameArray = ce.GetBindingXElementName();
                    if (beArray != null)
                    {
                        bdExprList.AddRange(beArray);
                    }
                    if (enameArray != null)
                    {
                        bingingXElementNameList.AddRange(enameArray);
                    }
                }
                foreach (BindingExpression bdExpr in bdExprList.Where(x => x != null))
                {
                    string[] bindingElementNames = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries);
                    if (bindingElementNames.Length == 1)
                    {
                        me.Add(new XElement(bindingElementNames[0], defaultValue));
                    }
                    else
                    {
                        if (me.Element(bindingElementNames[0]) == null)
                        {
                            me.Add(new XElement(bindingElementNames[0]));
                        }
                        me.Element(bindingElementNames[0]).Add(new XElement(bindingElementNames[1]));
                    }
                }

                foreach (var s in bingingXElementNameList)
                {
                    if (me.Element(s) == null)
                    {
                        me.Add(new XElement(s));
                    }
                }
            }
        }

        public static void cbo_EditableLostFocus(object sender, System.Windows.RoutedEventArgs e)
        {
            ComboBox cob = sender as ComboBox;

            var bdExpr = cob.GetBindingExpression(ComboBox.TextProperty);

            //绑定的成员节点名
            string bindElementName = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //显示成员的节点名称
            string displayMemberElementName = "";
            if (cob.DisplayMemberPath.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries).Count() > 0)
            {
                displayMemberElementName = cob.DisplayMemberPath.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
            }

            //设置数据源绑定节点的数据
            if (bdExpr.DataItem != null && cob.Text != (bdExpr.DataItem as XElement).Element(bindElementName).GetValue())
            {
                (bdExpr.DataItem as XElement).Element(bindElementName).SetValue(cob.Text);
            }
            //cob.LostFocus -= cbo_EditableLostFocus;

            //cob.MoveFocus(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.Next));

            //cob.LostFocus += cbo_EditableLostFocus;

            //e.Handled = true;
        }

        public static void cbo_LostFocus(object sender, System.Windows.RoutedEventArgs e)
        {
            if (e.OriginalSource.GetType() != typeof(ComboBox))
            {
                return;
            }
            ComboBox cob = sender as ComboBox;
            if (cob.SelectedIndex == -1)
            {
                return;
            }

            var bdExpr = cob.GetBindingExpression(ComboBox.SelectedValueProperty) ?? cob.GetBindingExpression(ComboBox.DisplayMemberPathProperty);

            //绑定的成员节点名
            string bindElementName = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //绑定选中项目值，因为SelectedValue不起作用
            string seleteValueElementName = cob.SelectedValuePath.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //cob.LostFocus -= cbo_LostFocus;
            //设置数据源绑定节点的数据
            object selectedValue;
            if (cob.SelectedItem is KeyValuePair<string, string>)
            {
                selectedValue = ((KeyValuePair<string, string>)cob.SelectedItem).Key;
            }
            else if (cob.SelectedItem is ComboBoxItem)
            {
                selectedValue = ((ComboBoxItem)cob.SelectedItem).Tag;
            }
            else
            {
                selectedValue = (cob.SelectedItem as XElement).Element(seleteValueElementName).Value;
            }
            if (selectedValue.ToString() != (bdExpr.DataItem as XElement).Element(bindElementName).Value)
            {
                (bdExpr.DataItem as XElement).Element(bindElementName).SetValue(selectedValue);
            }

            //cob.LostFocus += cbo_LostFocus;
            e.Handled = true;
        }

        public static void cbo_LostFocus2(object sender, System.Windows.RoutedEventArgs e)
        {

            ComboBox cob = sender as ComboBox;

            if (cob == null)
            {
                return;
            }
            if (cob.SelectedIndex == -1)
            {
                return;
            }

            var bdExpr = cob.GetBindingExpression(ComboBox.SelectedValueProperty) ?? cob.GetBindingExpression(ComboBox.DisplayMemberPathProperty);

            bdExpr = bdExpr ?? cob.GetBindingExpression(ComboBox.TextProperty);


            //绑定的成员节点名
            string bindElementName = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //绑定选中项目值，因为SelectedValue不起作用
            string seleteValueElementName = cob.SelectedValuePath.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //cob.LostFocus -= cbo_LostFocus;
            //设置数据源绑定节点的数据
            object selectedValue;
            if (cob.SelectedItem is KeyValuePair<string, string>)
            {
                selectedValue = ((KeyValuePair<string, string>)cob.SelectedItem).Key;
            }
            else if (cob.SelectedItem is ComboBoxItem)
            {
                selectedValue = ((ComboBoxItem)cob.SelectedItem).Tag;
            }
            else
            {
                selectedValue = (cob.SelectedItem as XElement).Element(seleteValueElementName).Value;
            }
            if (selectedValue.ToString() != (bdExpr.DataItem as XElement).Element(bindElementName).Value)
            {
                (bdExpr.DataItem as XElement).Element(bindElementName).SetValue(selectedValue);
            }

            //cob.LostFocus += cbo_LostFocus;
            e.Handled = true;
        }

        static void lb_LostFocus(object sender, System.Windows.RoutedEventArgs e)
        {
            ListBox lb = sender as ListBox;
            if (lb.SelectedIndex == -1)
            {
                return;
            }

            var bdExpr = lb.GetBindingExpression(ListBox.SelectedValueProperty) ?? lb.GetBindingExpression(ListBox.DisplayMemberPathProperty);
            if (bdExpr == null)
            {
                return;
            }
            //绑定的成员节点名
            string bindElementName = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //绑定选中项目值，因为SelectedValue不起作用
            string seleteValueElementName = lb.SelectedValuePath.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

            //cob.LostFocus -= cbo_LostFocus;
            //设置数据源绑定节点的数据
            object selectedValue;
            if (lb.SelectedItem is Dictionary<string, string>)
            {
                selectedValue = (lb.SelectedItem as Dictionary<string, string>)[seleteValueElementName];
            }
            else
            {
                selectedValue = (lb.SelectedItem as XElement).Element(seleteValueElementName).Value;
            }
            (bdExpr.DataItem as XElement).Element(bindElementName).SetValue(selectedValue);
            //cob.LostFocus += cbo_LostFocus;
            e.Handled = true;
        }


        ////增加这个事件，是因为ComboBox的SelectedValue绑定只能是单向的，原因未知(后改为Combox和ListBox通用)
        //public static void Selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
        //{
        //    Selector slt = sender as Selector;
        //    if (slt.SelectedIndex == -1 || slt.SelectedValue == null)
        //    {
        //        return;
        //    }

        //    string elementName = slt.SelectedValuePath.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];
        //    string newValue = (e.AddedItems[0] as XElement).Element(elementName).Value;

        //    var bdExpr = slt.GetBindingExpression(Selector.SelectedValueProperty);
        //    string elementName_dataSource = bdExpr.ParentBinding.Path.Path.Split(SeperatorArray, StringSplitOptions.RemoveEmptyEntries)[0];

        //    slt.SelectionChanged -= Selector_SelectionChanged;
        //    (bdExpr.DataItem as XElement).Element(elementName_dataSource).SetValue(newValue);
        //    slt.SelectionChanged += Selector_SelectionChanged;

        //    e.Handled = true;

        //}

        /// <summary>
        /// 从另外一个Element中获取相匹配的值
        /// </summary>
        /// <param name="me"></param>
        /// <param name="source"></param>
        /// <param name="exceptElementNames"></param>
        public static void SetMatchingElementValues(this XElement me, XElement source, params string[] exceptElementNames)
        {
            if (me == null)
                return;

            foreach (XElement x in me.Elements())
            {
                if (exceptElementNames != null && exceptElementNames.Contains(x.Name.LocalName))
                {
                    continue;
                }
                XElement xeMatch = source.Elements().SingleOrDefault(y => y.Name.LocalName.ToString().ToLower() == x.Name.LocalName.ToString().ToLower()); //不区分大小写
                if (xeMatch != null)
                {
                    if (x.Name.LocalName.EndsWith("List"))
                    {
                        if (x.HasElements)
                        {
                            x.RemoveAll();
                            x.Add(source.Element(x.Name.LocalName).Elements().ToArray());
                        }
                    }
                    else
                    {
                        if (x.HasElements || x.Name.LocalName.StartsWith("biz_")) //比如CIQ信息 
                        {
                            foreach (XElement xeSub in xeMatch.Elements())
                            {
                                x.SetElementValue(xeSub.Name.LocalName, xeSub.Value);
                            }
                        }
                        else
                        {
                            x.SetValue(xeMatch.Value);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 从另外一个Element中获取值，节点匹配的赋值，节点不匹配的节点添加到Me
        /// </summary>
        /// <param name="me"></param>
        /// <param name="source"></param>
        /// <param name="exceptElementNames"></param>
        public static void SetMatchingLeftElementValues(this XElement me, XElement source, params string[] exceptElementNames)
        {
            if (me == null)
                return;
            foreach (XElement x in source.Elements())
            {
                if (exceptElementNames != null && exceptElementNames.Contains(x.Name.LocalName))
                {
                    continue;
                }
                if (x.Name.LocalName.EndsWith("List") && x.HasElements)
                {
                    if (me.Element(x.Name) != null)
                        me.Element(x.Name).Remove();
                    me.Add(x);
                }
                else
                {
                    me.SetElementValue(x.Name, x.Value);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="me"></param>
        /// <param name="xes"></param>
        public static void SetElementElements(this XElement me, XElement[] xes)
        {
            if (me == null)
                return;
            me.Elements().Remove();
            me.Add(xes);
        }

        /// <summary>
        /// 获得XML结构下，节点值
        /// </summary>
        /// <param name="me"></param>
        /// <param name="elementNames"></param>
        /// <returns></returns>
        public static List<string> GetElementValues(this XElement me, params string[] elementNames)
        {
            List<string> elementValues = new List<string>();
            if (me == null)
                return elementValues;
            foreach (string x in elementNames)
            {
                if (me.Element(x) != null && me.Element(x).HasElements)
                {
                    continue;
                }
                else
                {
                    elementValues.Add(me.Element(x).Value);
                }
            }
            return elementValues;
        }

        public static void AssignElementValuesTo(this XElement me, XElement target, params string[] elementNames)
        {
            if (me == null)
                return;
            foreach (string x in elementNames)
            {
                if (me.Element(x) != null && me.Element(x).HasElements)
                {
                    if (target.Element(x) == null)
                    {
                        target.Add(me.Element(x));
                    }
                    else
                    {
                        target.Element(x).RemoveAll();
                        target.Element(x).Add(me.Element(x).Elements());
                    }
                }
                else
                {
                    target.SetElementValue(x, me.Element(x).Value);
                }
            }
        }


        public static void ClearElementValues(this XElement me, params string[] exceptElementNames)
        {
            foreach (XElement x in me.Elements())
            {
                if (exceptElementNames == null || !exceptElementNames.Contains(x.Name.LocalName))
                {
                    x.SetValue("");
                }
            }
        }

        #region 获得XElement值
        //获得XElement值
        public static T GetValue<T>(this XElement me, T defaultValue)
        {
            try
            {
                if (me == null || me.Value.Trim() == "")
                {
                    return defaultValue;
                }
                if (typeof(T) == typeof(Guid))
                {
                    return (T)Convert.ChangeType(new Guid(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(int))
                {
                    return (T)Convert.ChangeType(int.Parse(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(DateTime))
                {
                    return (T)Convert.ChangeType(DateTime.Parse(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(decimal))
                {
                    return (T)Convert.ChangeType(decimal.Parse(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(bool))
                {
                    return (T)Convert.ChangeType(bool.Parse(me.Value), typeof(T));
                }
                else
                {
                    return (T)Convert.ChangeType(me.Value, typeof(T));
                }
            }
            catch
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// 获取xml节点对象值
        /// </summary>
        /// <param name="xe">节点对象</param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetValue(this XElement xe, string defaultValue)
        {
            if (xe != null)
            {
                return xe.Value.Trim();
            }
            else
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// 获取xml节点对象值
        /// </summary>
        /// <param name="xe">节点对象</param>
        /// <returns></returns>
        public static string GetValue(this XElement xe)
        {
            return GetValue(xe, "");
        }

        public static string GetNotEmptyFormattedValue(this XElement me, string format)
        {
            if (me == null || me.Value == "")
            {
                return "";
            }
            return string.Format(format, me.Value);
        }
        #endregion

        #region 获取XAttribute值
        public static string GetValue(this XAttribute me, string defaultValue = "")
        {
            if (me != null)
            {
                return me.Value;
            }
            else
            {
                return defaultValue;
            }
        }
        public static T GetValue<T>(this XAttribute me, T defaultValue)
        {
            try
            {
                if (me == null || me.Value.Trim() == "")
                {
                    return defaultValue;
                }
                if (typeof(T) == typeof(Guid))
                {
                    return (T)Convert.ChangeType(new Guid(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(int))
                {
                    return (T)Convert.ChangeType(int.Parse(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(DateTime))
                {
                    return (T)Convert.ChangeType(DateTime.Parse(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(decimal))
                {
                    return (T)Convert.ChangeType(decimal.Parse(me.Value), typeof(T));
                }
                else if (typeof(T) == typeof(bool))
                {
                    return (T)Convert.ChangeType(bool.Parse(me.Value), typeof(T));
                }
                else
                {
                    return (T)Convert.ChangeType(me.Value, typeof(T));
                }
            }
            catch
            {
                return defaultValue;
            }
        }
        #endregion

        /// <summary>
        /// 拿一个业务对象与相应的对象比对，获取服务器端能识别的比对格式
        /// </summary>
        /// <param name="me"></param>
        /// <param name="xeCounterpart">副本</param>
        /// <returns></returns>
        public static XElement CompareTo(this XElement me, XElement xeCounterpart, params string[] reserverdElementNames)
        {
            if (me == null)
                return null;
            XElement xeDiff = new XElement(me.Name, new XAttribute("flag", "update"));
            foreach (XElement x in me.Elements().Where(x => !x.Name.LocalName.EndsWith("List") && !x.HasElements && new string[] { "CreateDate", "LastUpdateDate", "Flag" }.Contains(x.Name.LocalName) == false))  //只限于当前表的字段
            {
                if (xeCounterpart.Element(x.Name) != null)
                {
                    if (x.Value != xeCounterpart.Element(x.Name).Value)
                    {
                        xeDiff.Add(new XElement(x.Name, new XElement("NewValue", x.Value), new XElement("OldValue", xeCounterpart.Element(x.Name).Value)));
                    }
                }
            }
            if (xeDiff.HasElements)
            {
                foreach (string x in reserverdElementNames)
                {
                    if (xeDiff.Element(x) == null) //如果保留的字段已经是更新字段，就不必添加了
                    {
                        xeDiff.Add(xeCounterpart.Element(x));
                    }
                }
                return xeDiff;
            }
            else
            {
                return null;
            }
        }

        public static void RemoveSubElement(this XElement me, string subElementName)
        {
            if (me.Element(subElementName) != null)
            {
                me.Element(subElementName).Remove();
            }
        }


        ////Implemented based on interface, not part of algorithm
        //public static string RemoveAllNamespaces(this string xmlDocument)
        //{
        //    XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(xmlDocument));

        //    return xmlDocumentWithoutNs.ToString();
        //}

        //Core recursion function
        public static XElement RemoveAllNamespaces(this XElement xmlDocument)
        {
            if (!xmlDocument.HasElements)
            {
                XElement xElement = new XElement(xmlDocument.Name.LocalName);
                xElement.Value = xmlDocument.Value;
                return xElement;
            }
            return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
        }


        #region 设置元素值
        /// <summary>
        /// 设置元素值
        /// </summary>
        /// <param name="xe">元素</param>
        /// <param name="name">名称</param>
        /// <param name="value">值</param>
        /// <param name="isForceUpdate">是否强制更新</param>
        public static void SetElementValue(this XElement xe, XName name, object value, bool isForceUpdate)
        {
            //是否强制
            if (isForceUpdate || string.IsNullOrEmpty(xe.Element(name).GetValue()))
            {
                xe.SetElementValue(name, value);
            }

        }
        #endregion

        #region 拷贝数据
        /// <summary>
        /// 拷贝数据
        /// </summary>
        /// <param name="toItem">目标元素</param>
        /// <param name="fromItem">原元素</param>
        /// <param name="xeNames">需要拷贝的节点名称</param>
        public static void CopyData(this XElement toItem, XElement fromItem, params string[] xeNames)
        {
            CopyData(toItem, fromItem, true, xeNames);
        }
        #endregion

        #region 拷贝数据
        /// <summary>
        /// 拷贝数据
        /// </summary>
        /// <param name="toItem">目标元素</param>
        /// <param name="fromItem">原元素</param>
        /// <param name="xeNames">需要拷贝的节点名称</param>
        public static void CopyData(this XElement toItem, XElement fromItem, bool isForceUpdate, params string[] xeNames)
        {
            foreach (string name in xeNames)
            {
                string[] names = name.Split('|');
                if (names.Length == 2)
                {
                    toItem.SetElementValue(names[0], fromItem.Element(names[1]).GetValue(), isForceUpdate);
                }
                else
                {
                    toItem.SetElementValue(name, fromItem.Element(name).GetValue(), isForceUpdate);
                }
            }
        }
        #endregion

        #region 拷贝数据
        /// <summary>
        /// 拷贝数据
        /// </summary>
        /// <param name="item">源数据</param>
        /// <param name="xeNames">节点</param>
        /// <returns>返回拷贝后的数据</returns>
        public static XElement CopyData(this XElement item, params string[] xeNames)
        {

            XElement toItem = new XElement(item.Name);
            foreach (string name in xeNames)
            {
                string[] names = name.Split('|');
                if (names.Length == 2)
                {
                    toItem.SetElementValue(names[0], item.Element(names[1]).GetValue());
                }
                else
                {
                    toItem.SetElementValue(name, item.Element(name).GetValue());
                }
            }
            return toItem;
        }
        #endregion
    }
}
